import OpenGL
import OpenGL.GL
import OpenGL.GLU
import OpenGL.GLUT
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import math
from math import *
import Image

looping=True

# Stolen from http://pyopengl.sourceforge.net/context/nehe6.html
def loadImage( imageName  ):
        """Load an image file as a 2D texture using PIL

        This method combines all of the functionality required to
        load the image with PIL, convert it to a format compatible
        with PyOpenGL, generate the texture ID, and store the image
        data under that texture ID.

        Note: only the ID is returned, no reference to the image object
        or the string data is stored in user space, the data is only
        present within the OpenGL engine after this call exits.
        """
        im = Image.open(imageName)
        try:
                # get image meta-data (dimensions) and data
                ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBA", 0, -1)
        except SystemError:
                # has no alpha channel, synthesize one, see the
                # texture module for more realistic handling
                ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBX", 0, -1)
        # generate a texture ID
        ID = glGenTextures(1)
        # make it current
        glBindTexture(GL_TEXTURE_2D, ID)
        glPixelStorei(GL_UNPACK_ALIGNMENT,1)
        # copy the texture into the current texture ID
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)
        # return the ID for use
        return ID



class Monster:
    x=y=z=.6
    yaw=0.0
    pitch=0.0

PLAYER_SPEED=0.3
player=Monster()

def kbd(k,b,c):
    global looping
    if k=='q':
        looping=False
    if k=='w':
        player.x+=cos(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.y+=sin(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.z+=sin(player.pitch)*PLAYER_SPEED

    if k=='s':
        player.x-=cos(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.y-=sin(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.z-=sin(player.pitch)*PLAYER_SPEED
        
    if k=='a':
        player.x-=sin(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.y+=cos(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        
    if k=='d':
        player.x+=sin(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        player.y-=cos(player.yaw)*cos(player.pitch)*PLAYER_SPEED
        


prevx=0
prevy=0
def mouse(x,y):
    global prevx,prevy
    dx=prevx-x
    dy=prevy-y
    player.yaw+=dx*0.01
    player.pitch+=dy*0.01
    if player.pitch>1.57: player.pitch=1.57
    if player.pitch<-1.57: player.pitch=-1.57
    prevx=x
    prevy=y
    pass

def drawAxes():
    glBegin(GL_LINES)
    glColor3f(1,0,0)
    glVertex3f(0,0,0)
    glVertex3f(1,0,0)
    glColor3f(0,1,0)
    glVertex3f(0,0,0)
    glVertex3f(0,1,0)
    glColor3f(0,0,1)
    glVertex3f(0,0,0)
    glVertex3f(0,0,1)
    glEnd()

def setupLight():
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)
    glLightfv(GL_LIGHT0,GL_DIFFUSE,(1,1,1,1))
    glLightfv(GL_LIGHT0,GL_AMBIENT,(0,.3,.5,1))
    glLightfv(GL_LIGHT0,GL_POSITION,(100,100,100,0))

def drawSurface():
    dx=1.0
    dy=1.0
    def F(x,y):
        return sin(0.3*x)+sin(0.7*y)*sin(0.5*y)
    def CF(x,y):
        return (2+F(x,y))*0.25
    def CN(x,y):
        dzdx=F(x+1,y)-F(x,y)
        dzdy=F(x,y+1)-F(x,y)
        (x,y,z)=(-dzdx,-dzdy,1)
        ab=(x*x+y*y+z*z)**0.5
        return (x/ab,y/ab,z/ab)
        
        
    glBegin(GL_QUADS)
    glColor3f(.4,.8,.3)
    for a in xrange(20):
        for b in xrange(20):
            aa=a+1
            bb=b+1
            x=a*dx
            y=b*dy

            xx=aa*dx
            yy=bb*dy

            glColor3f(.4,CF(x,y),.3)
            glNormal3fv(CN(x,y))
            glTexCoord2f(x,y)
            glVertex3f(x,y,F(x,y))
            
            glColor3f(.4,CF(xx,y),.3)
            glNormal3fv(CN(xx,y))
            glTexCoord2f(xx,y)
            glVertex3f(xx,y,F(xx,y))

            glColor3f(.4,CF(xx,yy),.3)
            glNormal3fv(CN(xx,yy))
            glTexCoord2f(xx,yy)
            glVertex3f(xx,yy,F(xx,yy))

            glColor3f(.4,CF(x,yy),.3)
            glNormal3fv(CN(x,yy))
            glTexCoord2f(x,yy)
            glVertex3f(x,yy,F(x,yy))
            
    glEnd()

inited=False
tex1=0
def initOnce():
    global inited
    if inited: return
    inited=True
    global tex1
    tex1=loadImage("qwe.png")

def display():
    initOnce()
    glClearColor(.4,.5,.6,1.0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(90,1,0.1,100.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(player.x,player.y,player.z,
              player.x+cos(player.yaw)*cos(player.pitch),
              player.y+sin(player.yaw)*cos(player.pitch),
              player.z+sin(player.pitch),
              0,0,1)
    glEnable(GL_DEPTH_TEST)
    glEnable(GL_CULL_FACE)
    glEnable(GL_TEXTURE_2D)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
    glBindTexture(GL_TEXTURE_2D, tex1)
    setupLight()
    drawAxes()
    drawSurface()
    glutSwapBuffers()

def idle():
    display()

def main():
    glutInit()
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH)
    glutCreateWindow('qwe')
    glutDisplayFunc(display)
    glutKeyboardFunc(kbd)
    glutPassiveMotionFunc(mouse)
    while(looping):
        glutMainLoopEvent()
        glutPostRedisplay()
    pass


main()
